文化地景中的安平足跡#

導覽序言#

  台南安平,是台灣歷史最悠久的城鎮之一,擁有豐富的文化資產與自然景觀。將透過數位技術,結合地圖、影像、與互動元素,帶領讀者探索安平地區的文化地景變遷,以及水資源變遷的情形。以四個階段的互動式導覽,來展示安平的現代與歷史,並揭示自然環境隨時間的變遷。

_images/fish_market.jpg

Fig. 1 夜訪安平魚市場 2023/11/03 2:00AM#

第一部分: 安平漁港的變遷#

  安平漁港曾是台南的重要漁業中心,隨著時代的變遷,漁港的範圍與功能也不斷演變。安平漁港安平商港在地理位置上緊密相連,但其功能和歷史背景各有不同。安平漁港主要以漁業活動為核心,承載著台南漁民的生計與地方文化,而安平商港則隨著港口經濟的發展,逐漸成為一個重要的商業貿易樞紐。

  漁港與商港之間的關係,可以說是一種既合作又分工的模式。漁港承擔著漁獲的集散與處理,而商港則負責更大規模的貨物運輸與交易。隨著時代的進步,漁港的部分功能逐漸被商港所吸收,但漁港仍保有其文化象徵的意義,代表著台南的漁業傳統。

Hide code cell source
import folium
import base64
from folium import plugins
import math

# 設定焦點中心的經緯度座標
focus_center = [22.97996499492705, 120.16060291805357]
initial_zoom = 13

# 初始化地圖,設定中心點為焦點中心和縮放級別
m = folium.Map(location=focus_center, zoom_start=initial_zoom, width='100%', height='100%')

coordinates_port_old = [
    (22.98652226193982, 120.14314135883448),
    (22.98565817778794, 120.1409444821172),
    (22.985378954749702, 120.14107163351748),
    (22.98442526700474, 120.13867908760706),
    (22.984934837581722, 120.13615556442761),
    (22.980706818850855, 120.12537998238898),
    (22.983200936078912, 120.12423832536781),
    (22.98774615558894, 120.1358223824574),
    (22.99166494499389, 120.14000515442117),
    (22.992821678536387, 120.13859888818186),
    (22.990566171131253, 120.1362481419121),
    (22.990978367404296, 120.13579681182992),
    (22.993239139521492, 120.13810987485127),
    (22.996081228721575, 120.13500648026661),
    (22.996320811868777, 120.13499315166926),
    (22.996633840172887, 120.13531303507995),
    (22.998011013955782, 120.13673199166169),
    (22.99592425120849, 120.14003163778943),
    (22.993638821890464, 120.14227531419832),
    (22.993511772993838, 120.14343082369899),
    (22.997322084107026, 120.14540041173223),
    (22.999428610295368, 120.1448612584825),
    (22.999567960647628, 120.1454550882714),
    (22.99907725421138, 120.14558100058649),
    (23.00009950106809, 120.15026162834529),
    (22.99884569419394, 120.1505817141485),
    (22.998978977010758, 120.15120323863003),
    (22.99826753523976, 120.15138129880896),
    (22.99833495740817, 120.15169561047598),
    (23.000597480051425, 120.15347248683165),
    (23.000125154993214, 120.15491297111254),
    (23.000095879867953, 120.15539039507792),
    (22.999000244594257, 120.15518120806732),
    (22.99675633352673, 120.15549525134736),
    (22.995362363083533, 120.14956293282616),
    (22.99462869329082, 120.14888214163047),
    (22.991024951144666, 120.14887074829892),
    (22.99094590861329, 120.14785893884309),
    (22.989776797912388, 120.14720712993872),
    (22.988001996052315, 120.14494235745812),
    (22.989423017769944, 120.14369584465248),
    (22.98905427167945, 120.14321876348944),
    (22.98932581842077, 120.14293089649783),
    (22.98833205896235, 120.14163852682336),
    (22.98652226193982, 120.14314135883448)
]

# 定義安平商港經緯度座標
coordinates_port_new = [
    (22.959776096968785, 120.15161075610312),
    (22.96054636712402, 120.14875531313957),
    (22.962494443289447, 120.14747911673149),
    (22.965377913021804, 120.14727703408538),
    (22.97245665247682, 120.15537730276284),
    (22.97488485902668, 120.1529121378679),
    (22.977582556025066, 120.15237442862089),
    (22.983896912579212, 120.14899840536415),
    (22.984800659629585, 120.15130078133024),
    (22.976076644154084, 120.15904325714203),
    (22.97641188526243, 120.15938683851023),
    (22.97291838669799, 120.1621417046208),
    (22.97404267032466, 120.16350607814626),
    (22.97631045275247, 120.1616476962521),
    (22.977504773278458, 120.16066903747375),
    (22.981794930976378, 120.15715361378923),
    (22.984126153095954, 120.16052551973102),
    (22.985041571167752, 120.16136944933821),
    (22.984834026276243, 120.16176193269277),
    (22.98494562013618, 120.1659117770654),
    (22.98324629138883, 120.16588563505552),
    (22.98150444265588, 120.166909358707),
    (22.980505517503904, 120.17627194226337),
    (22.98269163082021, 120.17961800821804),
    (22.98246732571981, 120.18179619761978),
    (22.979620349436267, 120.1774401857557),
    (22.976695065778404, 120.17677447150888),
    (22.97650881596899, 120.17773251875612),
    (22.976190107881088, 120.1776595468422),
    (22.976376031826472, 120.17670316167325),
    (22.973606889393423, 120.17608515446345),
    (22.9733851397334, 120.17702115931692),
    (22.972977860809657, 120.17693019847886),
    (22.97320040324996, 120.17598697383805),
    (22.97072387404276, 120.17543060723251),
    (22.969992099805022, 120.17398003685702),
    (22.969260623795375, 120.1743873361258),
    (22.969025461468778, 120.17409083985739),
    (22.969792194455398, 120.17358541487752),
    (22.969092872350718, 120.17218464506755),
    (22.966599031960506, 120.174040532473),
    (22.96326930341673, 120.17591404200475),
    (22.96311081208907, 120.17613041475387),
    (22.96093679349121, 120.17679185667279),
    (22.959166567870437, 120.17609177820282),
    (22.9592118375472, 120.17297754396546),
    (22.959870657122547, 120.17296486214532),
    (22.961191671201284, 120.17263542279336),
    (22.96123132512282, 120.17343444810382),
    (22.961769509703263, 120.17343117806072),
    (22.961753697216363, 120.17249528892563),
    (22.96250111764567, 120.17230790566644),
    (22.963173886223895, 120.17191116962891),
    (22.96300610372072, 120.16926605849929),
    (22.965030143273903, 120.16851577410738),
    (22.967274410009395, 120.16695248196733),
    (22.966454227134804, 120.16565115559045),
    (22.959776096968785, 120.15161075610312)
]

# 目標點和參考點
reference_coord = (22.984934837581722, 120.13615556442761)
target_coord = (22.983253741376927, 120.1442680578393)

# 計算經度和緯度的平移差值
lat_diff = target_coord[0] - reference_coord[0]
lon_diff = target_coord[1] - reference_coord[1]

# 平移所有點位
coordinates_port_old = [(lat + lat_diff, lon + lon_diff) for lat, lon in coordinates_port_old]

# 計算多邊形面積的函數
def calculate_area(coords):
    earth_radius = 6371000  # 地球半徑(單位:米)
    area = 0.0
    for i in range(len(coords)):
        lat1, lon1 = math.radians(coords[i][0]), math.radians(coords[i][1])
        lat2, lon2 = math.radians(coords[(i + 1) % len(coords)][0]), math.radians(coords[(i + 1) % len(coords)][1])
        area += (lon2 - lon1) * (2 + math.sin(lat1) + math.sin(lat2))
    area = abs(area * earth_radius ** 2 / 2.0)
    return area

# 自定義函數計算兩點間的距離(Haversine公式)
def haversine(coord1, coord2):
    R = 6371  # 地球半徑,單位:公里
    lat1, lon1 = coord1
    lat2, lon2 = coord2
    dlat = math.radians(lat2 - lat1)
    dlon = math.radians(lon2 - lon1)
    a = math.sin(dlat / 2) ** 2 + math.cos(math.radians(lat1)) * math.cos(math.radians(lat2)) * math.sin(dlon / 2) ** 2
    c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a))
    return R * c

# 計算範圍資訊並添加到地圖
def add_area_info(coords, color, name, m, image_path=None):
    polyline = folium.PolyLine(locations=coords, color=color, weight=2.5)
    m.add_child(polyline)
    
    polygon = folium.Polygon(locations=coords, color=color, fill=True, fill_opacity=0.3)
    m.add_child(polygon)

    # 計算總距離和面積
    total_distance = sum(haversine(coords[i], coords[i + 1]) for i in range(len(coords) - 1))
    area = calculate_area(coords) / 1000000  # 轉換為平方公里

    # 中心點
    center_lat = sum(lat for lat, lon in coords) / len(coords)
    center_lon = sum(lon for lat, lon in coords) / len(coords)

    # 如果提供了圖片,將其轉換為 base64
    if image_path:
        with open(image_path, "rb") as image_file:
            encoded_image = base64.b64encode(image_file.read()).decode('utf-8')
        image_html = f'<img src="data:image/png;base64,{encoded_image}" width="300px" height="207px"><br>'
    else:
        image_html = ''

    # 添加標記和彈出信息
    if color == "red":
        popup_html = folium.Html(f"""
        <b>{name}</b><br>
        總邊長: {total_distance:.2f} 公里<br>
        總面積: {area:.2f} 平方公里<br>
        <br>
        <b>歷史發展</b><br>
        安平漁港的歷史可以追溯至數百年前,作為台南地區的漁業重<br>
        鎮,漁港見證了地方經濟和社會的發展。早期的安平漁港是一<br>
        個繁忙的小型漁業港口,台南的漁民在這裡進行日常的漁獲交<br>
        易和船隻維護。隨著清朝與日本統治時期的發展,漁港逐漸擴<br>
        展,其基礎設施也隨之改善。漁港的範圍和設施擴大,反映出<br>
        台南地區漁業活動的興盛。漁港成為地方漁民生活的中心,不<br>
        僅提供漁業生產的基礎,還帶動了地方經濟和社會文化的發展。<br>
        安平漁港也因此被視為台南地方文化的象徵之一。<br>
        {image_html}<br>
        影像來源:Google Earth Pro (2024)<br>
        """, script=True)
        popup = folium.Popup(popup_html, max_width=500)
        folium.Marker([center_lat, center_lon], popup=popup, icon=folium.Icon(icon='info-sign', color=color)).add_to(m)
    else:
        popup_html = folium.Html(f"""
        <b>{name}</b><br>
        總邊長: {total_distance:.2f} 公里<br>
        總面積: {area:.2f} 平方公里<br>
        <br>
        <b>崛起與發展</b><br>
        與安平漁港不同,安平商港的發展更多地反映了台南作為貿易<br>
        樞紐的重要性。商港的建立源於19世紀末和20世紀初的經濟需<br>
        求,隨著國際貿易的增長,安平的地理位置使其成為貿易的重<br>
        要節點。商港的擴建和現代化使得台南能夠處理更大規模的商<br>
        業貨物,從而促進了地方經濟的繁榮。安平商港的崛起也改變<br>
        了地方經濟的結構,原本以漁業為主的安平地區逐漸轉型為多<br>
        元化的經濟體系。商港不僅吸引了大量的國內外商船,還促進<br>
        了相關行業如倉儲、物流和製造業的發展。<br>
        {image_html}<br>
        影像來源:Google Earth Pro (2024)<br>
        """, script=True)
        popup = folium.Popup(popup_html, max_width=500)
        folium.Marker([center_lat, center_lon], popup=popup, icon=folium.Icon(icon='info-sign', color=color)).add_to(m)     
        

# 添加安平漁港和安平商港的範圍到地圖,並且加入圖片
add_area_info(coordinates_port_old, "red", "安平漁港", m, image_path="_static/map_google_earth_old.jpg")
add_area_info(coordinates_port_new, "blue", "安平商港", m, image_path="_static/map_google_earth_new.jpg")

# 添加重置視角的功能
plugins.Fullscreen(position='topright').add_to(m)

# 顯示地圖
m
Make this Notebook Trusted to load map: File -> Trust Notebook

Tip

動態展示:第一次開啟可能需耗時5分鐘以上。
Binder

操作說明:透過點擊地圖上的標記點,可以查看安平漁港的詳細歷史說明,去了解當時的社會背景與漁業發展。

第二部分:安平漁港出海口的歷史演變#

  在1944年美軍二萬五千分之一地形圖上,我們可以觀察到安平漁港的出海口已經開通。這與日治時期末期的歷史發展相符,日本在1930年代對安平漁港進行了一系列改良工程,包括開通新的出海口和連接出海口的港口運河。這些工程的完成標誌著安平漁港從一個逐漸淤積的舊港口轉型為具備更好通航條件的現代化港口,為當地的漁業和商業活動提供了新的發展契機。

Hide code cell source
from IPython.display import IFrame, display

# 定義HTML文件路徑
satellite_comparison_path = "_static/map_comparison.html"

# 使用IFrame嵌入對比結果
display(IFrame(src=satellite_comparison_path, width="100%", height="530px"))

Tip

操作說明:
可以點擊並滑動分隔條來左右移動,觀察不同年份的地圖對比。滑塊左側顯示的是OSM開放街圖,右側顯示的是1944年美軍二萬五千分之一地形圖。

資料來源:
中研院GIS專題中心 台灣百年歷史地圖

第三部分:安平漁港出海口的近代變遷#

  安平漁港的出海口在2003年時還處於封閉狀態。然而隨著時間的推移,這個封閉的出海口逐漸被打通,漁港與外海的連接變得更加順暢,從而提升了漁港的功能性和使用效率。而我們將透過2003年和2023年的衛星影像對比顯示,在過去20年間,安平漁港出海口有了什麼樣的變化。

Hide code cell source
from IPython.display import IFrame, display

# 定義HTML文件路徑
satellite_comparison_path = "_static/satellite_comparison.html"

# 使用IFrame嵌入對比結果
display(IFrame(src=satellite_comparison_path, width="100%", height="750px"))

Tip

操作說明:
可以點擊並滑動分隔條來左右移動,觀察不同年份的衛星影像對比。滑塊左側顯示的是2003年的影像,右側顯示的是2023年的影像。

第四部分:水域偵測影像對比#

  此影像主要運用水域指標(NDWI)技術來偵測水體。偵測結果以藍色表示水域,白色表示陸地,這種高對比的呈現方式使得水體範圍變得一目了然,旨在幫助使用者更好地辨識安平地區的水域分佈,並比較不同時期水體的變化。

Hide code cell source
from IPython.display import IFrame, display

# 定義HTML文件路徑
water_comparison_path = "_static/water_comparison.html"

# 使用IFrame嵌入對比結果
display(IFrame(src=water_comparison_path, width="100%", height="750px"))

Tip

操作說明:
可以點擊並滑動分隔條來左右移動,觀察不同年份的水域偵測影像對比。滑塊左側顯示的是2003年的影像,右側顯示的是2023年的影像。

第五部分:安平垂釣分享#

  這部分我將分享在安平地區的垂釣經歷。安平不僅以其深厚的歷史文化背景而聞名,還是垂釣愛好者的理想場所。

Hide code cell source
import folium
import base64
from PIL import Image
from PIL.ExifTags import TAGS, GPSTAGS
from folium import CustomIcon
from folium import IFrame, CustomIcon
import os

# 提取圖片中的 EXIF 資料,包括 GPS 資訊和日期時間
def get_exif_data(image):
    exif_data = {}
    info = image._getexif()
    if info:
        for tag, value in info.items():
            tag_name = TAGS.get(tag, tag)
            if tag_name == "GPSInfo":
                gps_data = {}
                for t in value:
                    sub_tag = GPSTAGS.get(t, t)
                    gps_data[sub_tag] = value[t]
                exif_data[tag_name] = gps_data
            else:
                exif_data[tag_name] = value
    return exif_data

# 將 EXIF 中的 GPS 資訊轉換為經緯度座標
def get_coordinates(gps_info):
    def to_degrees(value):
        d, m, s = value
        return d + (m / 60.0) + (s / 3600.0)

    lat = to_degrees(gps_info['GPSLatitude'])
    if gps_info['GPSLatitudeRef'] != "N":
        lat = -lat

    lon = to_degrees(gps_info['GPSLongitude'])
    if gps_info['GPSLongitudeRef'] != "E":
        lon = -lon

    return lat, lon

# 設置地圖的中心點
focus_center = [22.97893813775643, 120.15552999002338]
initial_zoom = 14
m = folium.Map(location=focus_center, zoom_start=initial_zoom, width='100%', height='100%')

# 照片所在的資料夾
photo_folder = "./_static/fishing_photo/"  # 替換為你的照片資料夾路徑
icon_path = "./_static/fish.png"  # 替換為你的自定義圖標路徑

# 遍歷資料夾中的所有照片
for filename in os.listdir(photo_folder):
    if filename.lower().endswith(('jpg', 'jpeg', 'png')):
        photo_path = os.path.join(photo_folder, filename)
        
        # 讀取照片並提取 EXIF 資訊
        image = Image.open(photo_path)
        exif_data = get_exif_data(image)
        
        # 確保照片有GPS信息
        if 'GPSInfo' in exif_data:
            coordinates = get_coordinates(exif_data['GPSInfo'])

            # 提取日期和時間資訊
            date_time = exif_data.get('DateTime', '未知')
            date, time = date_time.split(' ') if ' ' in date_time else (date_time, '未知')
            date = date.replace(':', '/')  # 將日期格式轉換為 YYYY/MM/DD
            time = time[:5]  # 去掉時間中的秒數,只保留時:分

            # 將照片轉換為 base64 編碼
            with open(photo_path, "rb") as image_file:
                encoded_image = base64.b64encode(image_file.read()).decode('utf-8')

            # 構建照片的 HTML 標籤
            image_html = f'<img src="data:image/jpeg;base64,{encoded_image}" width="300px"><br>'

            # 創建 Popup
            popup_html = folium.Html(f"""
                <b>垂釣紀錄</b><br>
                {image_html}
                日期: {date}<br>
                時間: {time}<br>
                """, script=True)

            popup = folium.Popup(popup_html, max_width=350)

            # 使用自定義圖標
            custom_icon = CustomIcon(icon_image=icon_path, icon_size=(50, 50))

            # 添加標記到地圖
            folium.Marker(coordinates, popup=popup, icon=custom_icon).add_to(m)





# Google 街景 URL 列表
street_view_urls = [
    ("https://www.google.com/maps/embed?pb=!4v1724791211385!6m8!1m7!1sCAoSLEFGMVFpcE5tMUJCUHNSTWtwVXJlWHZxZGhTZ1dOMTN3VFJJVTZRVFlTdWhf!2m2!1d22.9862649!2d120.1446358!3f67.98918716916899!4f1.0524643963972977!5f0.7820865974627469", [22.9862649, 120.1446358]),
    ("https://www.google.com/maps/embed?pb=!4v1724796717218!6m8!1m7!1sCAoSLEFGMVFpcE45OG1RbWwyQi0tVmNnOXQzU3pQamdGNlVCVzdMd3J1eGN4VlFj!2m2!1d22.9838544!2d120.1445198!3f124.77995270161149!4f4.046029018418778!5f0.7820865974627469", [22.9838544, 120.1445198]),
    ("https://www.google.com/maps/embed?pb=!4v1724796887689!6m8!1m7!1sCAoSLEFGMVFpcE9rS29aVVhlVUV2empKNzBNX0VmSTVxVlQycWotU2RlbU5wbXhO!2m2!1d22.9628334!2d120.1474533!3f175.21800633280415!4f-9.05878328105561!5f0.7820865974627469", [22.9628334, 120.1474533]),
    ("https://www.google.com/maps/embed?pb=!4v1724796947234!6m8!1m7!1sCAoSLEFGMVFpcFBKOXJHX2hkaU1GOFBOTkgxOFotOEN6RFpIbUIzVnZaM1o2RDU2!2m2!1d22.9604704!2d120.1490449!3f331.8262525362121!4f1.2963331583649165!5f0.7820865974627469", [22.9604704, 120.1490449])
]

# 添加多個標記到地圖,並為每個標記設置不同的街景 URL 和位置
for url, coords in street_view_urls:
    iframe = IFrame(html=f'<iframe src="{url}" width="450" height="300"></iframe>', width=450, height=300)
    popup = folium.Popup(iframe, max_width=500)
    folium.Marker(location=coords, popup=popup, icon=folium.Icon(icon='info-sign')).add_to(m)

# 保存並顯示地圖
m
Make this Notebook Trusted to load map: File -> Trust Notebook

Tip

操作說明:
顯示一個以安平地區為中心的互動地圖,其中包含釣魚照片的標記點和相關的 Google 街景連結。每個標記點上會彈出對應的照片、拍攝日期和時間,並使用自定義圖標進行標記。

結語#

  這次展示是透過數位的方式,為大家提供了一個探索台南安平地區文化地景的窗口。我們運用了數種數據資源和地理信息技術,重點展示了安平漁港和安平商港的歷史變遷以及水域變化,從安平漁港的歷史演變,到出海口的開通,再到近年來水域範圍的變化,這些都顯示出自然環境和人類活動對該地區的影響。